#include "Fingerprint-device.h"
#include <stdio.h>

// #define PRINT_TAG 1

FingerPrintDevice::FingerPrintDevice(const string &device)
    : uart(device, 57600)
{
}

bool FingerPrintDevice::sendPacket(const vector<uint8_t> &packet)
{
    return uart.writeData(packet.data(), packet.size()) < 0 ? false : true;
}

bool FingerPrintDevice::recvPacket(vector<uint8_t> &packet)
{

    vector<uint8_t> packet1(PACKET_FIX_LEN);
    int ret = uart.readFixLenData(packet1.data(), packet1.size());
    if (ret < 0)
    {
        fprintf(stderr, "Fail to readFixLenData\n");
        return false;
    }

    FingerprintProtocol protocol = FingerprintProtocol::fromProtocolPacket(packet1);
    vector<uint8_t> packet2(protocol.getPacketDataLen() + 2);

    ret = uart.readFixLenData(packet2.data(), packet2.size());
    if (ret < 0)
    {
        fprintf(stderr, "Fail to readFixLenData\n");
        return false;
    }

    packet.insert(packet.end(), packet1.begin(), packet1.end());
    packet.insert(packet.end(), packet2.begin(), packet2.end());

    return true;
}

bool FingerPrintDevice::clearFingerPrintLib(void)
{
    FingerprintProtocol protocol = FingerprintProtocol::makeClearFingerPrintProtocol();
    bool ok = sendPacket(protocol.getPakcet());
    if (!ok)
    {
        fprintf(stderr, "Fail to sendPacket\n");
        return false;
    }

#if PRINT_TAG
    printf("-------------sendPacket----------------\n");
    protocol.showPacket();
#endif

    vector<uint8_t> ackPacket;
    ok = recvPacket(ackPacket);
    if (!ok)
    {
        fprintf(stderr, "Fail to recvPacket\n");
        return false;
    }

    FingerprintProtocol ackProtocol = FingerprintProtocol::fromProtocolPacket(ackPacket);
    if (ackProtocol.isPacketError())
    {
        fprintf(stderr, "recv packet is error\n");
        return false;
    }

#if PRINT_TAG
    printf("-------------RecvPacket----------------\n");
    ackProtocol.showPacket();
#endif

    uint8_t ackCode = ackProtocol.getPacketData()[0];
    return ackCode ? false : true;
}

bool FingerPrintDevice::deleteFingerprint(const uint16_t pos)
{
    FingerprintProtocol protocol = FingerprintProtocol::makeDeleteFingerPrintProtocol(pos);
    bool ok = sendPacket(protocol.getPakcet());
    if (!ok)
    {
        fprintf(stderr, "Fail to sendPacket\n");
        return false;
    }

#if PRINT_TAG
    printf("-------------sendPacket----------------\n");
    protocol.showPacket();
#endif

    vector<uint8_t> ackPacket;
    ok = recvPacket(ackPacket);
    if (!ok)
    {
        fprintf(stderr, "Fail to recvPacket\n");
        return false;
    }

    FingerprintProtocol ackProtocol = FingerprintProtocol::fromProtocolPacket(ackPacket);
    if (ackProtocol.isPacketError())
    {
        fprintf(stderr, "recv packet is error\n");
        return false;
    }

#if PRINT_TAG
    printf("-------------RecvPacket----------------\n");
    ackProtocol.showPacket();
#endif

    uint8_t ackCode = ackProtocol.getPacketData()[0];
    return ackCode ? false : true;
}

/**
 * 发送握手包
 */
bool FingerPrintDevice::handshake(void)
{
    FingerprintProtocol protocol = FingerprintProtocol::makeHandshakeProtocol();
    bool ok = sendPacket(protocol.getPakcet());
    if (!ok)
    {
        fprintf(stderr, "Fail to sendPacket\n");
        return false;
    }
#if PRINT_TAG
    printf("-------------sendPacket----------------\n");
    protocol.showPacket();
#endif

    vector<uint8_t> ackPacket;
    ok = recvPacket(ackPacket);
    if (!ok)
    {
        fprintf(stderr, "Fail to recvPacket\n");
        return false;
    }

    FingerprintProtocol ackProtocol = FingerprintProtocol::fromProtocolPacket(ackPacket);
    if (ackProtocol.isPacketError())
    {
        fprintf(stderr, "recv packet is error\n");
        return false;
    }
#if PRINT_TAG
    printf("-------------RecvPacket----------------\n");
    ackProtocol.showPacket();
#endif
    uint8_t ackCode = ackProtocol.getPacketData()[0];
    return ackCode ? false : true;
}

bool FingerPrintDevice::detectImage(void)
{
    FingerprintProtocol protocol = FingerprintProtocol::makeDetectImageProtocol();
    bool ok = sendPacket(protocol.getPakcet());
    if (!ok)
    {
        fprintf(stderr, "Fail to sendPacket\n");
        return false;
    }
#if PRINT_TAG
    printf("-------------sendPacketDetectImage----------------\n");
    protocol.showPacket();
#endif
    vector<uint8_t> ackPacket;
    ok = recvPacket(ackPacket);
    if (!ok)
    {
        fprintf(stderr, "Fail to recvPacket\n");
        return false;
    }

    FingerprintProtocol ackProtocol = FingerprintProtocol::fromProtocolPacket(ackPacket);
    if (ackProtocol.isPacketError())
    {
        fprintf(stderr, "recv packet is error\n");
        return false;
    }
#if PRINT_TAG
    printf("-------------RecvPacketDetectImage----------------\n");
    ackProtocol.showPacket();
#endif
    uint8_t ackCode = ackProtocol.getPacketData()[0];
    return ackCode ? false : true;
}

bool FingerPrintDevice::makeImageFeature(uint8_t bufferID)
{
    FingerprintProtocol protocol = FingerprintProtocol::makeImageFeatureProtocol(bufferID);
    bool ok = sendPacket(protocol.getPakcet());
    if (!ok)
    {
        fprintf(stderr, "Fail to sendPacket\n");
        return false;
    }
#if PRINT_TAG
    printf("-------------sendPacket----------------\n");
    protocol.showPacket();
#endif

#if PRINT_DETAIL_TAG
    printf("----------打印生成特征发送数据包------------------\n");
    vector<uint8_t> packet = protocol.getPakcet();
    for (auto data : packet)
    {
        printf("%02x", data);
    }
    printf("\n");
#endif
    vector<uint8_t> ackPacket;
    ok = recvPacket(ackPacket);
    if (!ok)
    {
        fprintf(stderr, "Fail to recvPacket\n");
        return false;
    }

    FingerprintProtocol ackProtocol = FingerprintProtocol::fromProtocolPacket(ackPacket);
    if (ackProtocol.isPacketError())
    {
        fprintf(stderr, "recv packet is error\n");
        return false;
    }
#if PRINT_DETAIL_TAG
    printf("----------打印生成特征接收数据包------------------\n");
    vector<uint8_t> Rcvpacket = ackProtocol.getPakcet();
    for (auto data : Rcvpacket)
    {
        printf("%02x", data);
    }
    printf("\n");
#endif
#if PRINT_TAG
    printf("-------------RecvPacket----------------\n");
    ackProtocol.showPacket();
#endif
    uint8_t ackCode = ackProtocol.getPacketData()[0];
    return ackCode ? false : true;
}

bool FingerPrintDevice::generateImageTemplate(void)
{
    FingerprintProtocol protocol = FingerprintProtocol::makeImageTemplateProtocol();
    bool ok = sendPacket(protocol.getPakcet());
    if (!ok)
    {
        fprintf(stderr, "Fail to sendPacket\n");
        return false;
    }
#if PRINT_TAG
    printf("-------------sendeImageTemplatePacket----------------\n");
    protocol.showPacket();
#endif

#if PRINT_DETAIL_TAG

    printf("----------打印发送数据包------------------\n");
    vector<uint8_t> packet = protocol.getPakcet();
    for (auto data : packet)
    {
        printf("%02x", data);
    }
    printf("\n");
#endif
    vector<uint8_t> ackPacket;
    ok = recvPacket(ackPacket);
    if (!ok)
    {
        fprintf(stderr, "Fail to recvPacket\n");
        return false;
    }

    FingerprintProtocol ackProtocol = FingerprintProtocol::fromProtocolPacket(ackPacket);
    if (ackProtocol.isPacketError())
    {
        fprintf(stderr, "recv packet is error\n");
        return false;
    }
#if PRINT_TAG
    printf("-------------RecvImageTemplatePacket----------------\n");
    ackProtocol.showPacket();
#endif
    uint8_t ackCode = ackProtocol.getPacketData()[0];
    return ackCode ? false : true;
}

bool FingerPrintDevice::storeImageTemplate(uint16_t pos)
{
    FingerprintProtocol protocol = FingerprintProtocol::makeStoreTemplateProtocol(pos);
    bool ok = sendPacket(protocol.getPakcet());
    if (!ok)
    {
        fprintf(stderr, "Fail to sendPacket\n");
        return false;
    }
#if PRINT_TAG
    printf("-------------sende storeImageTemplate----------------\n");
    protocol.showPacket();
#endif
#if PRINT_DETAIL_TAG
    printf("----------打印发送数据包------------------\n");
    vector<uint8_t> packet = protocol.getPakcet();
    for (auto data : packet)
    {
        printf("%02x", data);
    }
    printf("\n");
#endif

    vector<uint8_t> ackPacket;
    ok = recvPacket(ackPacket);
    if (!ok)
    {
        fprintf(stderr, "Fail to recvPacket\n");
        return false;
    }

    FingerprintProtocol ackProtocol = FingerprintProtocol::fromProtocolPacket(ackPacket);
    if (ackProtocol.isPacketError())
    {
        fprintf(stderr, "recv packet is error\n");
        return false;
    }
#if PRINT_TAG
    printf("-------------Recv storeImageTemplate----------------\n");
    ackProtocol.showPacket();
#endif
    uint8_t ackCode = ackProtocol.getPacketData()[0];
    return ackCode ? false : true;
}

// 录指纹
bool FingerPrintDevice::recordFingerprint(uint16_t pos)
{
    bool ok;
    int successMakeFreature = 0;
    for (int i = 0; i < 10; i++)
    {
        printf("-----------1探测是否有指纹------------\n");
        ok = detectImage();
        printf("----------- 2 生成特征码至少2次------------\n");
        cout << "detect Image ok :" << ok << endl;
        if (ok)
        {
            ok = makeImageFeature(successMakeFreature + 1);
            if (ok)
            {
                printf("生成特征码成功 次数 %d\n", successMakeFreature + 1);
                cout << "Image Feature ok :" << ok << endl;
                successMakeFreature++;
            }
            if (successMakeFreature >= 2)
            {
                break;
            }
        }
        sleep(1);
    }

    if (!ok)
    {
        return false;
    }

    printf("----------- 3 生成模版------------\n");
    ok = generateImageTemplate();
    if (!ok)
    {
        return false;
    }

    printf("-----------4 存储模版------------\n");
    ok = storeImageTemplate(pos);
    if (!ok)
    {
        return false;
    }

    return true;
}

bool FingerPrintDevice::searchFingerPrint(uint16_t &pos)
{
    FingerprintProtocol protocol = FingerprintProtocol::makeSearchFingerPrintProtocol();
    bool ok = sendPacket(protocol.getPakcet());
    if (!ok)
    {
        fprintf(stderr, "Fail to sendPacket\n");
        return false;
    }
#if PRINT_TAG
    printf("-------------sende searchFingerPrint----------------\n");
    protocol.showPacket();
#endif

#if PRINT_DETAIL_TAG
    printf("----------打印发送数据包------------------\n");
    vector<uint8_t> packet = protocol.getPakcet();
    for (auto data : packet)
    {
        printf("%02x", data);
    }
    printf("\n");
#endif

    vector<uint8_t> ackPacket;
    ok = recvPacket(ackPacket);
    if (!ok)
    {
        fprintf(stderr, "Fail to recvPacket\n");
        return false;
    }

    FingerprintProtocol ackProtocol = FingerprintProtocol::fromProtocolPacket(ackPacket);
    if (ackProtocol.isPacketError())
    {
        fprintf(stderr, "recv packet is error\n");
        return false;
    }
#if PRINT_TAG
    printf("-------------RecvImageTemplatePacket----------------\n");
    ackProtocol.showPacket();
#endif
    uint8_t *ackCode = ackProtocol.getPacketData();
    if (ackCode[0] != 0)
    {
        return false;
    }

    pos = (ackCode[1] << 8) | ackCode[2];

    return true;
}

bool FingerPrintDevice::verfiyFingerPrint(uint16_t &pos)
{
    // 1 生成特征
    bool ok = false;
    int successMakeFreature = 0;
    for (int i = 0; i < 10; i++)
    {
        // printf("-----------1探测是否有指纹------------\n");
        ok = detectImage();
        // printf("----------- 1 生成特征码至少1次------------\n");
        // cout << "detect Image ok :" << ok << endl;
        if (ok)
        {
            ok = makeImageFeature(successMakeFreature + 1);
            if (ok)
            {
                //  printf("生成特征码成功 次数 %d\n", successMakeFreature + 1);
                //  cout << "Image Feature ok :" << ok << endl;
                successMakeFreature++;
            }
            if (successMakeFreature >= 1)
            {
                break;
            }
        }
        sleep(1);
    }
    // 开始搜索
    return searchFingerPrint(pos);
}

bool FingerPrintDevice::isTouchState(void)
{
    const char *fileName = "/sys/class/gpio/gpio134/value";
    FILE *fp = fopen(fileName, "r");
    if (!fp)
    {
        if (errno == ENOENT)
        {
            system("echo 134 > /sys/class/gpio/export");
            system("echo in  > /sys/class/gpio/gpio134/direction");
            FILE *fp = fopen(fileName, "r");
            if (!fp)
            {
                fprintf(stderr, "Fail to fopen %s :%s \n", fileName, strerror(errno));
                return false;
            }
        }
        else
        {
            fprintf(stderr, "Fail to fopen %s :%s \n", fileName, strerror(errno));
            return false;
        }
    }

    int level = fgetc(fp);
    fclose(fp);
    return level == '1' ? true : false;
}
